
#include "ednn.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

char *ednn_strncpy(char *dst, const char *src, ednn_size_t n)
{
	if (n != 0)
	{
		char *d = dst;
		const char *s = src;

		do
		{
			if ((*d++ = *s++) == 0)
			{
				/* NUL pad the remaining n-1 bytes */
				while (--n != 0)
				*d++ = 0;
				break;
			}
		} while (--n != 0);
	}

	return (dst);
}

void ednn_list_init(ednn_list_t *list)
{
    list->next = list->prev = list;
}

int ednn_list_isempty(const ednn_list_t *head)
{
	return ((head->next == head) && (head->prev == head));
}

void ednn_list_append(ednn_list_t *n, ednn_list_t *existing)
{
	existing->prev->next = n;
	
	n->next = existing;
	n->prev = existing->prev;
	
	existing->prev = n;
}

void ednn_strb_setup(ednn_strb_t *s, char *buff, int len)
{
    s->head = buff;
    s->len  = 0;
    s->max  = len;
    s->p    = buff;
}

int ednn_strb_build(ednn_strb_t *bpr, const char *fmt, ...)
{
	int len;
	va_list ap;
	
	va_start(ap, fmt);
	len = ednn_vsnprintf(bpr->p, bpr->max, fmt, ap);
	va_end(ap);

	bpr->max -= len;
	bpr->len += len;
	bpr->p += len;
	
	return len;
}

void (*ednn_assert_hook)(const char *ex, const char *func, ednn_size_t line);

void ednn_assert_set_hook(void (*hook)(const char *, const char *, ednn_size_t))
{
	ednn_assert_hook = hook;
}

void ednn_assert_handler(const char *ex_string, const char *func, ednn_size_t line)
{
	volatile char dummy = 0;
	
	if (ednn_assert_hook == EDNN_NULL) {
		ednn_err("Assert(%s) %s:%d", ex_string, func, line);
		while (dummy == 0);
	} else {
		ednn_assert_hook(ex_string, func, line);
	}
}

static ednn_uint8_t ednn_log_level = CONFIG_EDNN_LOG_LEVEL;

static struct ednn_loglevel ednn_loglevel_strings[] = {
    {NULL, EDNN_LOG_NONE},
    {"D",  EDNN_LOG_DEBUG},
    {"I",  EDNN_LOG_INFO},
    {"N",  EDNN_LOG_NOTICE},
    {"E",  EDNN_LOG_ERR}
};

void ednn_log(ednn_uint8_t level, const char *func, int line, const char *format, ...)
{
    int len, max;
    va_list args;
    char buff[CONFIG_EDNN_LOG_MAXSIZE] = {'\0'}, *pos;

    /* mask some level */
    if (level < ednn_log_level) {
        return;
    }

    pos = buff;
    len = 0;
    max = CONFIG_EDNN_LOG_MAXSIZE;

    /* build level */
    len = ednn_snprintf(pos, max, "[%s] ",
        ednn_loglevel_strings[level].string);
    max -= len;
    pos += len;

#if (CONFIG_EDNN_LOG_FUNC == 1)
    /* build function name and line number */
    len = ednn_snprintf(pos, max, "[%s:%d] ", func, line);
    max -= len;
    pos += len;
#endif
    
    va_start(args, format);
    len = ednn_vsnprintf(pos, max, format, args);
    va_end(args);
    max -= len;
    pos += len;

    len = ednn_snprintf(pos, max, "\n");

    ednn_printf(buff);
}